package rsj.exception;

import com.rlyy.aibase.utils.base.Box;
import common.util.BoxUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import rsj.context.ApplicationContextUtil;

import java.lang.reflect.Method;
import java.util.Map;

/**
 * 注册异常解析器
 *
 * @author yuanqinglong
 * @since 2021/8/17 17:01
 */
@Configuration
public class MyExceptionResolver {

    private final Logger logger = LoggerFactory.getLogger(MyExceptionResolver.class);

    /**
     * 注册异常异常解析器
     *
     * @return {@link ExceptionHandlerExceptionResolver}
     */
    @Bean
    protected ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver() {
        ExceptionHandlerExceptionResolver exceptionHandlerExceptionResolver = new ExceptionHandlerExceptionResolver();
        exceptionHandlerExceptionResolver.setApplicationContext(ApplicationContextUtil.getApplicationContext());
        return exceptionHandlerExceptionResolver;
    }

    /**
     * 异常处理程序方法解析器缓存
     */
    @Value("#{exceptionHandlerExceptionResolver.exceptionHandlerAdviceCache}")
    private Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerMethodResolverMap;


    /**
     * 调用异常处理目标方法
     *
     * @param exception 抛出的异常
     * @return 返回异常处理方法封装的结果
     */
    public Box invokeExceptionMethod(Box in, Throwable exception) {
        // 获取处理此异常的异常处理bean和对应方法
        HandlerMethod exceptionHandlerMethod = this.getExceptionHandlerMethod(exception);
        try {
            // 调用执行统一异常处理方法 返回异常处理方法封装的数据
            return (Box) exceptionHandlerMethod.getMethod().invoke(exceptionHandlerMethod.getBean(), exception, in);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("统一异常处理错误: ", e.getCause());
            // 调用默认的异常处理器
            return BoxUtil.errorBox(in, "服务器忙");
        }
    }

    /**
     * 获取异常处理类和方法
     *
     * @param exception 抛出的异常信息
     * @return 返回对应的异常处理类和方法
     */
    protected HandlerMethod getExceptionHandlerMethod(Throwable exception) {
        // 遍历初始化标注了@ControllerAdvice和@RestControllerAdvice的缓存映射器
        for (Map.Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : exceptionHandlerMethodResolverMap.entrySet()) {
            ControllerAdviceBean controllerAdvice = entry.getKey();
            // 异常和处理方法的映射关系
            ExceptionHandlerMethodResolver resolver = entry.getValue();
            // 处理异常要调用的统一异常处理方法
            Method method = resolver.resolveMethodByThrowable(exception);
            if (method != null) {
                return new HandlerMethod(controllerAdvice.resolveBean(), method);
            }
        }
        return null;
    }
}
